メインコンテンツへスキップ

PowerDNS で自宅 DNS サーバの構築 (Rocky10編)

はじめに #

この記事は、 PowerDNS で自宅 DNS サーバの構築 (Rocky Linux 9) の更新版である。 Rocky Linux 10 上に (前回と構成を若干変更して) PowerDNS のパッケージ群を使って自宅用の DNS サーバを構築する手順を記載する。

自宅DNSサーバ構成 #

この記事では、下記のような構成で構築する。

項目 設定
ハードウェア Proxmox VE が構築済みの仮想環境
OS Rocky Linux 10 (LXC コンテナ)
メモリ 2GB
ストレージ 20GB
DNS 権威サーバ PowerDNS Authoritative Server
DNS リゾルバ PowerDNS Recursor
DNS バックエンド DB MariaDB
DNS 権威サーバ用 WebUI PowerDNS-Admin (Docker)

前回の記事では PowerDNS DNSdist を組み込んでいたが、簡単なドメインの振分けなら Recursor でも可能なことがわかったため、構成から外している。

DNS サーバ構成図 #

自宅DNSサーバ構成図

構築手順 #

設定パラメータ #

各サーバの設定値を先にまとめておく。記事内のスクリプトの値を、各自の環境に合わせて書き換えること。

システム 項目 設定
DNSサーバ ホスト名 dns01
DNSサーバ IPv4 アドレス 192.0.2.50/24
DNSサーバ IPv4 デフォルトゲートウェイ 192.0.2.1
DNSサーバ IPv6 アドレス 2001:DB8::32/64
DNSサーバ IPv6 デフォルトゲートウェイ 2001:DB8::1/64
DNSサーバ 上位DNSフォワード先アドレス 1.1.1.1
1.0.0.1
2606:4700:4700::1111
2606:4700:4700::1001
MariaDB バージョン 11.8 (LTS) ※サポート期限: 2033/10/22
MariaDB root パスワード 6g8nS9QSC5HDhdbx
MariaDB pdnsadmin ユーザーパスワード 3mwH1QeuiMV53157
PowerDNS Authoritative Server バージョン 5.0.x
PowerDNS Authoritative Server DNS Listen Port UDP/TCP 25301
PowerDNS Authoritative Server API KEY faa5b1ce-1495-4fce-9129-735078a675f2
PowerDNS Authoritative Server API Listen port 8081
PowerDNS Recursor バージョン 5.4.x
PowerDNS Recursor Listen Port UDP/TCP 53
PowerDNS-Admin バージョン 0.4.2
PowerDNS-Admin Listen Port TCP 9191
DNSゾーン ゾーン名 home
DNSゾーン IPv4 セグメント 192.0.2.0/24
DNSゾーン IPv6 セグメント 2001:DB8::/64
  • IPv4 / IPv6 アドレスは、それぞれ RFC 5737 / RFC 3849 に従って例示用アドレスを記載している
  • パスワードは develop.tools | パスワード生成ツール で作成
  • API キーは develop.tools | UUID生成ツール で作成
  • 「上位DNSフォワード先アドレス」はプロバイダ提供の IP アドレス、または Public DNS を指定
    • 例では Cloudflare の IPv4/IPv6 アドレスを指定している

MariaDB インストール #

dnf リポジトリ設定 #

MariaDB 11.8 LTS版 の例:

MARIADBVERSION=11.8
cat <<__EOT__> /etc/yum.repos.d/mariadb.repo
[mariadb]
name = MariaDB
baseurl = https://rpm.mariadb.org/${MARIADBVERSION}/rhel/\$releasever/\$basearch
gpgkey= https://rpm.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
__EOT__

インストール

dnf install -y MariaDB-server
systemctl enable mariadb
systemctl start mariadb

MariaDB 初期設定 #

初期セキュリティ設定値

mariadb-secure-installation
Enter current password for root (enter for none):  [Enter]
Switch to unix_socket authentication [Y/n]  y[Enter]
Change the root password? [Y/n] y[Enter]
6g8nS9QSC5HDhdbx
6g8nS9QSC5HDhdbx
# MariaDB の root ユーザーのパスワードを2回入力
Remove anonymous users? [Y/n] y[Enter]
Disallow root login remotely? [Y/n] y[Enter]
Remove test database and access to it? [Y/n] y[Enter]
Reload privilege tables now? [Y/n] y[Enter]

MariaDB 設定変更 #

/etc/my.cnf.d/server.cnf を vi で編集

  • 警告メッセージの抑制
  • bind アドレスをローカルループバックのみに変更
[mysqld]
log_warnings = 1
bind-address = 127.0.0.1,::1

MariaDB 初回ログイン #

パスワードを聞かれるので、設定したパスワードでログイン

# mariadb -u root -p
Enter password: 6g8nS9QSC5HDhdbx[Enter]
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 299
Server version: 11.8.7-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> 

PowerDNS 用のユーザーを設定

CREATE DATABASE pdns;
GRANT ALL ON pdns.* TO pdnsadmin@localhost IDENTIFIED BY '3mwH1QeuiMV53157';
FLUSH PRIVILEGES;

設定確認

SHOW GRANTS FOR pdnsadmin@localhost;

下記の中身が表示されればOK

Grants for pdnsadmin@localhost

[Ctrl]-[D] で抜ける

PowerDNS パッケージ群インストール #

リポジトリセットアップ #

参考: https://repo.powerdns.com/

PowerDNS Authority 5.0 / PowerDNS Recursor 5.4 の例

PDNS_AUTH_VER=50
PDNS_RECURSOR_VER=54
curl -o /etc/yum.repos.d/powerdns-auth-${PDNS_AUTH_VER}.repo https://repo.powerdns.com/repo-files/el-auth-${PDNS_AUTH_VER}.repo
curl -o /etc/yum.repos.d/powerdns-rec-${PDNS_RECURSOR_VER}.repo https://repo.powerdns.com/repo-files/el-rec-${PDNS_RECURSOR_VER}.repo

パッケージインストール #

dnf install -y pdns pdns-backend-mysql pdns-recursor

PowerDNS 用に MariaDB セットアップ #

DBのパスワードを聞かれたら入力:

mariadb -u pdnsadmin -p pdns < /usr/share/doc/pdns-backend-mysql/schema.mysql.sql
Enter password:

PowerDNS Auth (Authoritative Server) / Recursor 設定 #

PDNS Auth オリジナル設定バックアップ:

cp -a /etc/pdns/pdns.conf /etc/pdns/pdns.conf.DEFAULT
PDNS_AUTH_BASE='/etc/pdns'
PDNS_RECURSOR_BASE='/etc/pdns-recursor'
PDNS_RECURSOR_IPV4_ACL='192.0.2.0/24'
PDNS_RECURSOR_IPV6_ACL='2001:DB8::/64'
PDNS_RECURSOR_LOCAL_ZONE='home'
PDNS_RECURSOR_LOCAL_PTRZONEV4='2.0.192.in-addr.arpa'
# IPv6 の逆引きを登録する場合
PDNS_RECURSOR_LOCAL_PTRZONEV6='0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa'
# UUID生成ツール等で作成
PDNS_AUTH_APIKEY='faa5b1ce-1495-4fce-9129-735078a675f2'
MARIADB_PASSWORD='3mwH1QeuiMV53157'
# CloudFlare の場合
UPSTREAM_DNS_IPv4_1=1.1.1.1
UPSTREAM_DNS_IPv4_2=1.0.0.1
UPSTREAM_DNS_IPv6_1=2606:4700:4700::1111
UPSTREAM_DNS_IPv6_2=2606:4700:4700::1001

# PDNS Auth config
cat <<__EOT__ >${PDNS_AUTH_BASE}/pdns.conf
api=yes
api-key=${PDNS_AUTH_APIKEY}
webserver=yes
webserver-address=0.0.0.0
# Enable access from Docker bridge network
webserver-allow-from=127.0.0.0/8,172.29.0.0/16
webserver-port=8081
launch=gmysql
gmysql-socket=/var/lib/mysql/mysql.sock
gmysql-user=pdnsadmin
gmysql-password=${MARIADB_PASSWORD}
gmysql-dbname=pdns
local-address=127.0.0.1 ::1
local-port=25301
security-poll-suffix=
setgid=pdns
setuid=pdns
# log-dns-details=yes
# log-dns-queries=yes
log-timestamp=yes
# logging-facility=0
# loglevel=7
dnsupdate=yes
allow-dnsupdate-from="127.0.0.0/8, ::1/128"
__EOT__
chgrp pdns ${PDNS_AUTH_BASE}/pdns.conf
chmod 640 ${PDNS_AUTH_BASE}/pdns.conf

# PDNS Recursor config (YAML形式)
cat <<__EOT__ >${PDNS_RECURSOR_BASE}/recursor.d/recursor.yml
incoming:
  listen:
    - 0.0.0.0
    - ::
  allow_from:
    - 127.0.0.0/8
    - "${PDNS_RECURSOR_IPV4_ACL}"
    - '::1/128'
    - "${PDNS_RECURSOR_IPV6_ACL}"
  tcp_fast_open: 100
outgoing:
  tcp_fast_open_connect: true
  source_address: 
    - 0.0.0.0
    - '::'
recursor:
  extended_resolution_errors: true
  serve_rfc1918: false
  hint_file: no-refresh
  forward_zones:
    - zone: '${PDNS_RECURSOR_LOCAL_ZONE}'
      forwarders:
        - '127.0.0.1:25301'
    - zone: '${PDNS_RECURSOR_LOCAL_PTRZONEV4}'
      forwarders:
        - '127.0.0.1:25301'
    # IPv6 の逆引きゾーン登録
    - zone: '${PDNS_RECURSOR_LOCAL_PTRZONEV6}'
      forwarders:
        - '[::1]:25301'
  forward_zones_recurse:
    - zone: .
      forwarders:
        - ${UPSTREAM_DNS_IPv4_1}
        - ${UPSTREAM_DNS_IPv4_2}
        - ${UPSTREAM_DNS_IPv6_1}
        - ${UPSTREAM_DNS_IPv6_2}
  security_poll_suffix: ''
dnssec:
  negative_trustanchors:
    - name: '${PDNS_RECURSOR_LOCAL_ZONE}'
      reason: 'private zone'
    - name: '${PDNS_RECURSOR_LOCAL_PTRZONEV4}'
      reason: 'private ptr zone'
    # IPv6 の逆引きゾーン登録(NTA)
    - name: '${PDNS_RECURSOR_LOCAL_PTRZONEV6}'
      reason: 'private ptr zone'
logging:
  loglevel: 4
  # common_errors: true
  # quiet: false
  timestamp: true
  # trace: false
__EOT__

# rsyslog のログ振分け設定
mkdir -p /var/log/powerdns
chmod 755 /var/log/powerdns
cat <<'__EOT__' > /etc/rsyslog.d/powerdns.conf
$template PowerDNSLogs, "/var/log/powerdns/%programname%.log"

if $programname contains 'pdns-recursor' then -?PowerDNSLogs
& stop

if $programname contains 'pdns_server' then -?PowerDNSLogs
& stop
__EOT__

# logrotate 設定
cat <<__EOT__ > /etc/logrotate.d/powerdns
/var/log/powerdns/*.log
{
    missingok
    sharedscripts
    postrotate
        /usr/bin/systemctl -s HUP kill rsyslog.service >/dev/null 2>&1 || true
    endscript
}
__EOT__

systemctl reload rsyslog.service
systemctl enable pdns-recursor.service
systemctl restart pdns-recursor.service
systemctl enable pdns.service
systemctl restart pdns.service
DNSSEC の NTA (Negative Trust Anchor) とは

NTA とは、DNSSEC の検証を特定のゾーンに対して無効化する仕組みである。(RFC 7646)

DNSSEC は DNS レスポンスの改ざんをデジタル署名で検出する技術で、ルートゾーン (.) から目的のドメインまで「信頼の連鎖 (Chain of Trust)」が繋がっていることを前提とする。連鎖が途切れていると、リゾルバは応答を SERVFAIL として破棄する。

自宅用に作成したプライベートゾーン (home、逆引きゾーン等) はグローバル DNS に存在しないため、ルートから辿れる DS レコードがなく、信頼の連鎖が存在しない。このため PowerDNS Recursor がデフォルトの DNSSEC 検証を行うと、ローカルゾーンへの問い合わせがすべて SERVFAIL になる。

NTA として登録することで「このゾーンは DNSSEC を検証しなくてよい」と Recursor に明示でき、ローカル名前解決が正常に動作するようになる。

なお、Recursor 5.0 から NTA の指定を直接 recursor.yml に記載できるようになったため、 従来の nta.lua による別途指定は不要 になった。

PowerDNS Authoritative Server へのゾーン登録例 #

初期登録テスト用として、ゾーン情報を pdnsutil コマンドで登録する。 pdnsutil コマンドの書式が 4.9 → 5.0 で変更になっているので注意。

ZONE="home"
PTR_ZONE="2.0.192.in-addr.arpa"
SOA_MASTER="dns01.${ZONE}."
SOA_CONTACT="hostmaster.${ZONE}."
SOA_SERIAL=0
SOA_REFRESH=28800 # 8 hours
SOA_RETRY=3600 # 1 hour
SOA_EXPIRE=2419200 # 28 days
SOA_NEGATIVE=900 # 15 minutes
SOA_RECORD="${SOA_MASTER} ${SOA_CONTACT} ${SOA_SERIAL} ${SOA_REFRESH} ${SOA_RETRY} ${SOA_EXPIRE} ${SOA_NEGATIVE}"

# clear zone
pdnsutil zone delete "${ZONE}"
pdnsutil zone delete "${PTR_ZONE}"

## SAMPLE ZONE ENTRY ##
# 正引きゾーン作成
pdnsutil zone create "${ZONE}"
pdnsutil zone set-kind "${ZONE}" native
pdnsutil rrset replace "${ZONE}" @ SOA "${SOA_RECORD}"
pdnsutil rrset add "${ZONE}" @ NS dns01.${ZONE}.

# DNSサーバ自身の正引き登録
pdnsutil rrset add "${ZONE}" dns01 A 192.0.2.50
pdnsutil rrset add "${ZONE}" dns01 AAAA '2001:DB8::32'

# 逆引きゾーン作成
pdnsutil zone create "${PTR_ZONE}" 
pdnsutil zone set-kind "${PTR_ZONE}" native
pdnsutil rrset replace "${PTR_ZONE}" @ SOA "${SOA_RECORD}"
pdnsutil rrset add "${PTR_ZONE}" @ NS dns01.${ZONE}.

# DNSサーバ自身の逆引き登録
pdnsutil rrset add "${PTR_ZONE}" 50 PTR dns01.home.

PowerDNS の WebUI を追加 #

docker engine 導入 #

dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
dnf install -y docker-ce docker-compose-plugin
# デフォルトブリッジネットワーク アドレスプールの変更
cat <<'__EOT__' >/etc/docker/daemon.json
{
    "default-address-pools":[  
        {  
            "base":"172.29.0.0/16",
            "size":24
        }
    ]
}
__EOT__
# start dockerd
systemctl enable docker.service
systemctl start docker.service

PowerDNS-Admin 導入 (docker) #

作成済みの PowerDNS Authoritative Server 用 API KEY を貼る。

docker run -d \
    -e SECRET_KEY='faa5b1ce-1495-4fce-9129-735078a675f2' \
    -v pda-data:/data \
    -p 9191:80 \
    --restart always \
    powerdnsadmin/pda-legacy:latest

firewalld 設定 #

firewalld を使う場合は、下記のポート利用に合わせて開放ルールを追加する。

ポート プロトコル プロセス 用途 対応方針
53 TCP/UDP pdns-recursor DNS(allow_from で LAN 限定済み) LAN から許可
9191 TCP docker-proxy PowerDNS-Admin Web UI LAN から許可
# インストールされていない場合
dnf install -y firewalld
systemctl enable --now firewalld

# ゾーン割り当て
firewall-cmd --permanent --zone=internal --add-interface=eth0
firewall-cmd --permanent --zone=trusted  --add-interface=docker0

# internal ゾーン(LAN 向け)許可ルール
firewall-cmd --permanent --zone=internal --add-service=dns
firewall-cmd --permanent --zone=internal --add-port=9191/tcp

firewall-cmd --reload

PowerDNS-Admin 初回設定 #

ブラウザでアクセス http://192.0.2.50:9191/

PowerDNS-Admin ログイン画面

ユーザー登録する

  • Create an account
  • First Name: FIRSTNAME
  • Last Name: LASTNAME
  • Email: [email protected]
  • Username: xxxx
  • Password: XXXXXXXXX

WebUI内で設定
※わかりにくいが、PowerDNS Authoritative Server の IP は、Docker ブリッジネットワークから見たホスト自身になるため、docker0 ブリッジの先頭 IP アドレスを指定する。

  • PowerDNS API URL: http://172.29.0.1:8081/
  • PowerDNS API Key: faa5b1ce-1495-4fce-9129-735078a675f2

設定が完了すると、Web UI からゾーン編集ができるようになる。

PowerDNS-Admin コンソール

動作確認 #

再起動後のサービス確認 #

プロセス確認

ps axuw | grep "pdns"

pdns_server, pdns_recursor のプロセスが上がっているか確認。

pdns         443  0.0  1.2 750864 26436 ?        SLsl May23   0:15 /usr/sbin/pdns_server --guardian=no --daemon=no --disable-syslog --log-timestamp=no --write-pid=no
pdns-re+  518848  0.0  1.3 421508 28728 ?        Ssl  12:03   0:00 /usr/sbin/pdns_recursor --daemon=no --write-pid=no --disable-syslog --log-timestamp=no

ログにエラーが出ていないか確認

less /var/log/powerdns/pdns_server.log
less /var/log/powerdns/pdns-recursor.log

外部問合せテスト #

サーバ上の dig コマンドでテスト。

# dig +noall +ans @localhost blog.yamk.net A
blog.yamk.net.          300     IN      A       104.21.21.177
blog.yamk.net.          300     IN      A       172.67.199.171
# dig +noall +ans @localhost blog.yamk.net AAAA
blog.yamk.net.          300     IN      AAAA    2606:4700:3033::6815:15b1
blog.yamk.net.          300     IN      AAAA    2606:4700:3032::ac43:c7ab

内部問合せテスト #

# dig +noall +ans @localhost dns01.home A
dns01.home.             3600    IN      A       192.0.2.50
# dig +noall +ans @localhost dns01.home AAAA
dns01.home.             3600    IN      AAAA    2001:DB8::32

逆引きも試す。

# dig +noall +ans @localhost -x 192.0.2.50
50.2.0.192.in-addr.arpa. 3600 IN      PTR     dns01.home.

PC端末から問合せテスト #

PC端末の Windows PowerShell から、DNS サーバを指定して問い合わせてみる。
Resolve-DnsName コマンドレットでは -Type A_AAAA オプションで IPv4 と IPv6 アドレスを同時にクエリできる。

外部ホスト

Resolve-DnsName -Name blog.yamk.net -Server 192.0.2.50 -Type A_AAAA
Name              Type   TTL   Section    IPAddress
----              ----   ---   -------    ---------
blog.yamk.net     AAAA   176   Answer     2606:4700:3033::6815:15b1
blog.yamk.net     AAAA   176   Answer     2606:4700:3032::ac43:c7ab
blog.yamk.net     A      99    Answer     172.67.199.171
blog.yamk.net     A      99    Answer     104.21.21.177

内部ホスト正引き

Resolve-DnsName -Name dns01.home -Server 192.0.2.50 -Type A_AAAA
Name              Type   TTL   Section    IPAddress
----              ----   ---   -------    ---------
dns01.home        AAAA   3600  Answer     2001:DB8::32
dns01.home        A      3600  Answer     192.0.2.50

内部ホスト逆引き

Resolve-DnsName -Name 192.0.2.50 -Server 192.0.2.50 -Type PTR
Name                        Type   TTL   Section    NameHost
----                        ----   ---   -------    --------
50.2.0.192.in-addr.arpa     PTR    3600  Answer     dns01.home

仕上げ #

もろもろテストして問題なさそうなら、家庭内 LAN の DHCP サーバで配布している DNS サーバのアドレスを、上で構築した DNS サーバに変更する。念のため、フォールバック先として元の DNS サーバも残しておく。

例:

  • プライマリ DNS サーバ: 192.0.2.50 ※新規構築した DNS
  • セカンダリ DNS サーバ: 192.0.2.1 ※元々の DNS サーバ(ブロードバンドルータなど)

各端末の参照先が新規 DNS サーバに向いたら、さらにテストを繰り返して安定性を確認する。

以上。

余談 #

ブロードバンドルータやホームゲートウェイ内蔵の DNS 機能ではなく、敢えて独立 DNS サーバを用意することで ネットが快適になる。構築リソースとか維持コスト等の状況が許すなら自宅 DNS 構築はお勧めである。自力で構築したからといって、すべてが解決するわけではないが、得るものは必ずある。

ただし DNS の知識はそれなりに必要なので、中途半端な運用で上位 ISP に迷惑を掛けないよう心がけたい。

「自宅 DNS」の2つの意味 #

自宅 (または小規模の事務所など) の DNS として求められているものは、主に2つある。

(1) 外部インターネットアクセス用の DNS #

Webサイト閲覧や各種動画アプリ、ネットワークゲーム、オンラインサービス等で、外部へアクセスするときは必ず DNS が使用される。

PC やスマホ端末から現代的な Web サイトを見る場合、1回のアクセスでも JavaScript やフォントダウンロード・アクセス解析・広告など、多数のサイトに横断して複雑な送受信が走る。

一方、近年普及してきた Akamai や Cloudflare に代表される CDN (コンテンツデリバリネットワーク) は、

  • 世界中に多数のコンテンツサーバが配置され
  • 問い合わせるたびにホスト IP が変わる (冗長化+ネットワーク距離最適化)

という特徴があるため、DNS キャッシュ保持時間が短く設定されている。すなわち、同じ URL へのアクセスでも頻繁に DNS リクエストが発生する。

DNS キャッシュとか DNS プロキシといった機能は、ブロードバンドルータや ISP が提供するホームゲートウェイにも内蔵されている。ただし制御範囲が狭く、大抵「名前解決のパフォーマンス」もそれなりであるため、DNS の応答速度向上は体感に影響する。

また IPv6 の普及により応答データ量が DNS 当初の仕様 (512バイト) を越えることも多くなったため、レスポンスが落ちる TCP フォールバックではなく、EDNS0 によるメッセージサイズ拡張 に対応していてほしい。

ブロードバンドルータの DNS の不具合で、インターネットアクセスが不安定になってしまった事例もある。

(2) ローカルサーバ用の DNS #

Linux サーバを複数立て始めると、欲しくなってくるのが内部ホスト名でのアクセスである。

古くは NBT (NetBIOS over TCP/IP), Apple の Bonjour, LLMNR, 最近では mDNS といった 同じセグメント内で自動的にホスト名とIPアドレスを紐づけるといった技術 は存在するが、ブロードキャストやマルチキャストが届く範囲でしか名前解決できないため、セグメントを分けた瞬間にホスト名が見えなくなってしまう。

自分の場合、仮想環境内に仮想ルータを立ててセグメントを分けたり、外部から VPN で自宅 LAN に入ってきたりしているので、分かりやすいホスト名でアクセスできるようにしておきたい。

「ホスト名+ドメイン」と「IPアドレス」を直接紐づけるサーバを 権威サーバ (Authoritative Server) と呼び、ブロードバンドルーター・ホームゲートウェイにも簡易版がついていることもあるが、あまり使いやすくはない。

自宅ネットワーク内の各種ホスト名は変化するので、Web 管理画面等でメンテナンスしやすくしておきたい。

PowerDNS 所感 #

  • PowerDNS Recursor は、2024年1月の 5.0 から設定ファイルが YAML に移行したが、Authoritative Server は 2026年5月現在も従来形式のまま。
  • 性能はともかく、同じブランドであれば設定方法も統一してほしい‥‥。

参考 #